package org.pathlet.core;

import java.util.List;
import java.util.Map;

import org.pathlet.core.config.ConfigManager;
import org.pathlet.core.exception.ResourceDuplicationException;
import org.pathlet.core.exception.ResourceException;

/**
 *
 * 1. Contained all <code>ResourceFactory</code> objects.
 * 2. Provide the filter mechanism to located different <code>ResourceFactory</code> against different path.
 * 3. Cache all resources which be retrieved by getResource method.
 *
 * @author Charlie Zhang
 *
 */
public interface PathletContainer {

	/**
	 * Get alias map object. Map.key is the "to" property, May.value is the "from" property
	 * @return
	 */
	Map<Path, Path> getAliases();

	ConfigManager getConfigManager();

	ModuleManager getModuleManager();

	String[] getScopes();

	/**
	 * PathClassLoader is readonly property. It could not be changed after the PathletContainer construct.
	 * @return
	 */
	PathClassLoader getPathClassLoader();

	/**
	 * Add <code>Resource</code> directory into this <code>ResourceFactory</code>.
	 * <code>ResourceFactory</code> will cache this added <code>Resource</code>.
	 *
	 *
	 * @param resource
	 * @throws ResourceDuplicationException when exists a resource in same path, this exception will be thrown.
	 */
	void addResource(PathletResource resource) throws ResourceDuplicationException;


	/**
	 * Get Resource by path
	 *
	 * @param fullPath
	 * @return
	 * @throws ResourceException
	 */
	PathletResource getResource(Path fullPath) throws ResourceException;


	List<ResourceInstanceEvent> getInstanceEvents();

	/**
	 * Get the path by the type.
	 * @param type the ClassName of the type
	 * @return
	 */
	Path getPathByType(String type);


	/**
	 * Get Instance by path，in Container Space.
	 * @param path
	 * @return
	 */
	default <T> T getInstance(Path path) {
		return getContainerSpace().getInstance(path);
	}

	/**
	 * Get Instance by path，in Container Space.
	 * @param path
	 * @return
	 */
	default <T> T  getInstance(String path) {
		return getContainerSpace().getInstance(new Path(path));
	}

	/**
	 * 获得指定scope下，指定绑定对象的InstanceSpace实例，并从InstanceSpace实例中获得指定path的实例对象。
	 * @param scope 作用域
	 * @param bindingObject 绑定对象(每个namespace都会绑定到一个对象上, 如：web应用中的每个ServletRequest绑定到一个InstanceSpace实例)
	 * @param path 资源路径
	 * @return
	 */
	default <T> T getInstance(String scope, Object bindingObject, Path path) {
		return getSpace(scope, bindingObject, true).getInstance(path);
	}

	/**
	 * 获得指定scope下，指定绑定对象的InstanceSpace实例，并从InstanceSpace实例中获得指定path的实例对象。
	 * @param scope 作用域
	 * @param bindingObject 绑定对象(每个namespace都会绑定到一个对象上, 如：web应用中的每个ServletRequest绑定到一个InstanceSpace实例)
	 * @param path 资源路径
	 * @return 指定path的实例对象
	 */
	default <T> T getInstance(String scope, Object bindingObject, String path) {
		return getSpace(scope, bindingObject, true).getInstance(new Path(path));
	}



	/**
	 *
	 * Flush the matched resource in cache and targets in all contexts cache.
	 * FIXME Please think about the multithread environments, and be verify the multiple threads resource synchronizing.
	 *
	 * @param matchPattern
	 */
	public void flush(PathPattern matchPattern);


	public InstanceSpace getSpace(String scope, Object bindingObject, boolean create);


	/**
	 * Container has its own InstanceSapce, which will create and destroy with the container create and destroy.
	 * @return
	 */
	public InstanceSpace getContainerSpace();

	/**
	 * Destroy the InstanceSpace which be bound with the "boundObject"
	 * @param scope
	 * @param boundObject
	 */
	public void destroySpace(String scope, Object boundObject);

	/**
	 * Destroy the container.
	 */
	public void destroy();


}
